﻿#include "stdafx.h"
#include "initskintk.h"
#include "Subclass.h"
#include "SkinButton.h"
#include "SkinStatic.h"
#include "SkinEdit.h"
#include "SkinScrollBar.h"
#include "SkinMainWnd.h"
#include "SkinListBox.h"
#include "SkinTreeCtrl.h"
#include "SkinListCtrl.h"
#include "SkinCombox.h"
#include "SkinProgress.h"
#include "SkinSpin.h"
#include "SkinSlider.h"
#include "SkinHeader.h"
#include "SkinTabCtrl.h"
#include "SkinStatusBar.h"
#include "SkinToolBar.h"
#include "SkinMDIClient.h"
#include "SkinControlBar.h"
#include "SkinDlg.h"
#include "SkinComboLBox.h"
#include "SkinMenu.h"

CInitSKinTK::CInitSKinTK(void)
:m_hPrevSkinHook(NULL)
{
    m_arrayWnd.RemoveAll();
}

CInitSKinTK::~CInitSKinTK(void)
{
	for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
	{
		CSkinWnd *pWnd = m_arrayWnd.GetAt(i);
	//	if(pWnd)
		//	delete pWnd;
	}
	m_arrayWnd.RemoveAll();
}
void CInitSKinTK::RemoveWnd(CSkinWnd *pWnd)
{
	for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
	{
		CSkinWnd *pSkin = m_arrayWnd.GetAt(i);

		if(pSkin == pWnd)
		{
			m_arrayWnd.RemoveAt(i);
			return;
		}
	}
}
void CInitSKinTK::RemoveWnd(HWND hWnd)
{
	CSkinWnd *pSkin = FindSkinWnd(hWnd);
	if(pSkin)
	{
		pSkin->InstallSkin(NULL);
		RemoveWnd(pSkin);
	}
}
CSkinWnd* CInitSKinTK::FindSkinWnd(HWND hWnd)
{
	for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
	{
		CSkinWnd *pWnd = m_arrayWnd.GetAt(i);

		if(pWnd->GetHwnd() == hWnd)
			return pWnd;
	}
	return NULL;
}
void CInitSKinTK::HookWindow(HWND hWnd)
{
	WindowType wndType = GetWindowType(hWnd);
	CSkinWnd *pSubWnd = NULL;
	switch(wndType)
	{
	case wtButton:
		{
			pSubWnd = new CSkinButton;
			break;
		}
	case wtStatic:
		{
			pSubWnd = new CSkinStatic;
			break;
		}
	case wtEdit:
		{
			pSubWnd = new CSkinEdit;
			break;
		}
    case wtMenu:
        {
            pSubWnd = new CSkinMenu;
            break;
        }
	case wtScrollBar:
		{
			pSubWnd = new CSkinScrollBar;
			break;
		}
	case wtListBox:
		{
			pSubWnd = new CSkinListBox;
			break;
		}
	case wtDlg:
		{
			pSubWnd = new CSkinDlg;
			break;
		}
	case wtTreeCtrl:
		{
			pSubWnd = new CSkinTreeCtrl;
			break;
		}
	case wtListCtrl:
		{
			pSubWnd = new CSkinListCtrl;
			break;
		}
	case wtComboBox:
		{
			pSubWnd = new CSkinCombox;
			break;
		}
	case wtCombolBox:
		{
			pSubWnd = new CSkinCombolBox;
			break;
		}
	case wtProgress:
		{
			pSubWnd = new CSkinProgress;
			break;
		}
	case wtUpDown:
		{
			pSubWnd = new CSkinSpin;
			break;
		}
	case wtTrackBar:
		{
			pSubWnd = new CSkinSlider;
			break;
		}
	case wtHeader:
		{
			pSubWnd = new CSkinHeader;
			break;
		}
	case wtTabCtrl:
		{
			pSubWnd = new CSkinTabCtrl;
			break;
		}
	case wttStatusBar:
		{
			pSubWnd = new CSkinStatusBar;
			break;
		}
	case wtToolBar:
		{
			pSubWnd = new CSkinToolBar;
			break;
		}
	case wtMDIClient:
		{
			pSubWnd = new CSkinMDIClient;
			break;
		}
	case wtFMCControlBar:
		{
			pSubWnd = new CSkinControlBar;
			break;
		}
	case wtFMCMDIFrame:
	case wtFMCFrame:
	case wtFMCMDIChild:
		{
			pSubWnd = new CSkinFrame;
			break;
		}
	}
	if(pSubWnd != NULL)
	{
		if (!pSubWnd->InstallSkin(hWnd))  
        {
            delete pSubWnd;
            return;
        }
		m_arrayWnd.Add(pSubWnd);
	}
}
WindowType CInitSKinTK::GetWindowType(HWND hWnd)
{
	DWORD lReturn;
	char szTemp[MAX_PATH];

	static char s_szClass[][32] = 
	{
		"Button",					// 按钮类			0
		"Edit",						// 编辑框类			1
		"ComboBox",					// 组合框类			2
		"ListBox",					//列表框			3
		"ScrollBar",				//					4
		"Static",					//					5
		"#32770",					//					6
		"#32768",					//popupMenu			7
		"msctls_hotkey32",			// 热键				8
		"SysIPAddress32",			// IP 地址			9
		"SysListView32",			// 列表查看			10
		"SysTreeView32",			// 树形查看			11
		"SysDateTimePick32",		// 日期/时间选择	12
		"msctls_updown32",			// 旋转				13
		"SysMonthCal32",			// 月历				14
		"SysTabControl32",			// TAB 控件			15
		"msctls_progress32",		// 进度条			16
		"msctls_trackbar32",		// 追踪条			17
		"ComboLBox",				//combo list		18	
		"SysHeader32",				//header			19
		"msctls_statusbar32",		//statusbar			20
		"ToolbarWindow32",			//statusbar			21
		"MDICLIENT"	,				//mdiclient			22					
		"AfxControlBar"				//controlbar		23

		"TButton",					// VCL TButton 类
		"ThunderCommandButton",		// Visual Basic Command Button 类
		"ThunderRT6CommandButton",	// Visual Basic Command Button 类
		"TCheckBox",
		"ThunderCheckBox",
		"ThunderRT6CheckBox",
		"TEdit",
		"TNumberEdit",
		"ThunderTextBox",
		"ThunderRT6TextBox",
		"TComboBox",
		"ThunderComboBox",
		"ThunderRT6ComboBox"		

	};

	// 查找判断匹配的类名称
	GetClassName(hWnd, szTemp, sizeof(szTemp));
	
	for (lReturn = 0; lReturn < (sizeof(s_szClass) / sizeof(s_szClass[0])); lReturn++)
		if (lstrcmpi(szTemp, s_szClass[lReturn]) == 0)
			break;
	switch (lReturn)
	{
	case 0:
		return wtButton;
	case 1:
		return wtEdit;
	case 2:
		return wtComboBox;
	case 3:
		return wtListBox;
	case 4:
		return wtScrollBar;
	case 5:
		return wtStatic;
	case 6:
		return wtDlg;
	case 7:
		return wtMenu;
	case 8:
		return wtHotKey;
	case 9:
		return wtIPAddress;
	case 10:
		return wtListCtrl;
	case 11:
		return wtTreeCtrl;
	case 12:
		return wtTimePick;
	case 13:
		return wtUpDown;
	case 15:
		return wtTabCtrl;
	case 16:
		return wtProgress;
	case 17:
		return wtTrackBar;
	case 18:
		return wtCombolBox;
	case 19:
		return wtHeader;
	case 20:
		return wttStatusBar;
	case 21:
		return wtToolBar;
	case 22:
		return wtMDIClient;
	}

	WindowType wt = GetWindowTypeEx(hWnd);
	if(wt != wtUnknow)
		return wt;
	return wtUnknow;
}
WindowType CInitSKinTK::GetWindowTypeEx(HWND hWnd)
{

	char szTemp[MAX_PATH];

	GetClassName(hWnd, szTemp, sizeof(szTemp));
	CString sClass(szTemp);
	
	if (sClass.Find("Afx") == 0) // its an mfc framework base or derived class
	{
		// can do the check if pWnd is permanent else mfc will not yet
		// have hooked up
		CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);

		if (pWnd)
		{
			// must do the check in order of most derived class first
			if (pWnd->IsKindOf(RUNTIME_CLASS(CView)))
				return wtFMCView;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
				return wtFMCMDIFrame;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd)))
				return wtFMCMDIChild;
		//	else if (pWnd->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)))
		//		return wtFMCMiniDockFrame;
			else if (pWnd->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
				return wtFMCMiniFrame;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) // this is the catch all for frame wnds
				return wtFMCFrame;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)))
				return wtFMCSplitter;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CDialogBar)))
				return wtFMCDialogBar;

			else if (pWnd->IsKindOf(RUNTIME_CLASS(CControlBar)))
				return wtFMCControlBar;

			else 
				return wtFMCWnd; // catch all for all window classes
		}
	}
	return wtUnknow;
}
LRESULT CALLBACK CInitSKinTK::SkinHookProc(int iCode, WPARAM wParam, LPARAM lParam)
{
	if ((((CWPSTRUCT *) lParam)->message == WM_CREATE) && (iCode >= 0))
	{
		GetInitskin().HookWindow(((CWPSTRUCT *) lParam)->hwnd);
	}
    // 对WM_NCDESTROY的处理在CSubClassWnd里有
	else if ((((CWPSTRUCT *) lParam)->message == WM_NCDESTROY) && (iCode >= 0))
	{
		/*HWND hWnd = ((CWPSTRUCT *) lParam)->hwnd;
		for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
		{
			CSkinWnd *pWnd = m_arrayWnd.GetAt(i);
			if(pWnd->GetHwnd() == hWnd)
			{
				pWnd->HookWindow((HWND)NULL);
				m_arrayWnd.RemoveAt(i);
				delete pWnd;
				break;
			}
		}*/
	}
	return CallNextHookEx(GetInitskin().m_hPrevSkinHook, iCode, wParam, lParam);
}

BOOL CALLBACK CInitSKinTK::SkinEnumChildProc(HWND hwnd, LPARAM lParam)
{
	GetInitskin().HookWindow(hwnd);
	EnumChildWindows(hwnd, SkinEnumChildProc, 0);
	return TRUE;
}

BOOL CALLBACK CInitSKinTK::SkinEnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
	GetInitskin().HookWindow(hwnd);
	EnumChildWindows(hwnd, SkinEnumChildProc, 0);
	return TRUE;
}

BOOL CALLBACK CInitSKinTK::ModifyEnumChildProc(HWND hwnd, LPARAM lParam)
{
    GetInitskin().HookWindow(hwnd);
	SendMessage(hwnd, WM_NCPAINT, (WPARAM)NULL, 0);
	InvalidateRect(hwnd,NULL,TRUE);
	UpdateWindow(hwnd);
	EnumChildWindows(hwnd, ModifyEnumChildProc, 0);
	return TRUE;
}

BOOL CALLBACK CInitSKinTK::ModifyEnumThreadWndProc(HWND hwnd, LPARAM lParam)
{
    GetInitskin().HookWindow(hwnd);
	SendMessage(hwnd, WM_NCPAINT, (WPARAM)NULL, 0);
	InvalidateRect(hwnd,NULL,TRUE);
	UpdateWindow(hwnd);
	EnumChildWindows(hwnd, ModifyEnumChildProc, 0);
	return TRUE;
}

void CInitSKinTK::InstallSkin(CString strFileName)
{
	GetSkin().LoadSkin(strFileName);    // 如果已经安装皮肤，会进行卸载操作
	//m_skinMenu.EnableHook(TRUE);  // SkinMenu已经重新构建
    // 对现有的进行hook
	EnumThreadWindows(GetCurrentThreadId(), ModifyEnumThreadWndProc, 0); 
    // 处理以后的
	m_hPrevSkinHook = SetWindowsHookEx(WH_CALLWNDPROC, SkinHookProc, 0, GetCurrentThreadId());
}
void CInitSKinTK::InstallSkin(HMODULE hModule, LPCTSTR lpName, LPCTSTR lpType)
{
    GetSkin().LoadSkin(hModule, lpName, lpType);
    //m_skinMenu.EnableHook(TRUE);
    EnumThreadWindows(GetCurrentThreadId(), SkinEnumThreadWndProc, 0); 
    m_hPrevSkinHook = SetWindowsHookEx(WH_CALLWNDPROC, SkinHookProc, 0, GetCurrentThreadId());
}
void CInitSKinTK::ChangeSkin(CString strFileName)
{
	GetSkin().LoadSkin(strFileName);
	for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
	{
		CSkinWnd *pWnd = m_arrayWnd.GetAt(i);
		if (!pWnd->LoadSkin())
		{
            delete pWnd;    // 没有对应的皮肤就卸载了
            RemoveWnd(pWnd);
		}
	}
}
void CInitSKinTK::ModifyHue(int nPercent)
{
	GetImages()->ModifyHue(nPercent);
	EnumThreadWindows(GetCurrentThreadId(), ModifyEnumThreadWndProc, 0); 
}
void CInitSKinTK::UnInstallSkin()
{

	UnhookWindowsHookEx(m_hPrevSkinHook);
	m_hPrevSkinHook = NULL;
	//m_skinMenu.EnableHook(FALSE);

    //GetSkin().ClearSkin();
	//for(int i = 0 ; i < m_arrayWnd.GetSize() ; i++)
	//{
	//	CSkinWnd *pWnd = m_arrayWnd.GetAt(i);
	//	pWnd->InstallSkin(NULL);
	////	if(pWnd)
	////		delete pWnd;
	//}
	m_arrayWnd.RemoveAll();

}

CInitSKinTK& CInitSKinTK::GetInitskin()
{
    static CInitSKinTK a;
    return a;
}